#ifndef HTTP_H
#define HTTP_H
#include "common.h"
#include "header.h"
#include "thread.h"
#include "cache_file.h"

typedef struct cache_control {
	int max_age;
	int s_maxage;
	int min_stale;
	int max_stale; 
	int min_fresh;	
	/* judgement */
	int public:1; /* The document is cacheable by any cache. */
	int private:1; /* The document is not cacheable by a shared cache. */
	int no_store:1;
	int no_cache:1;  /* can cache, but must revalidate */
	int only_if_cached:1; /* The client wants a copy only if it is in the cache */
	int no_transform:1; /* Do not convert the entity-body. Useful for applications that require that the message received is exactly what was sent by the server. */
	int proxy_revalidate: 1; /* Client must revalidate data except for private client caches. Public caches must verify the status of stale documents. Like must-revalidate, excluding private caches. */
	int must_revalidate:1; /* The cache must verify the status of stale documents, i.e., the cache cannot blindly use a document that has expired */
}cache_control_t;

enum HIT_STATE {
	TCP_NONE = -1,
	TCP_MISS = 0,
	TCP_HIT = 1, 
	TCP_REVALIDATE,
	TCP_REFRESH_HIT, 
	TCP_REFRESH_MISS,
	TCP_REFRESH_ERROR,
	TCP_SHM_HIT, 
	TCP_MEM_HIT,
};

enum DATA_SEND_STATE {
	DATA_NONE, 
	DATA_REPLY_IN,
	DATA_MEM_CACHE, 
	DATA_SHM_CACHE, 
	DATA_DISK,
};

typedef struct {
	int low;
	int high;
	int shm_fd;
	int size;
	void *start;
}mmap_t;

typedef struct {
	int header_size;
	int body_size;
	int header_out;
	int body_out; 
	int body_in;
	int parsed;
	int header_send;
	int statu;
	int cacheable;
	http_version_t version;
	header_t *headers;
	mem_t *in;  /* from socket or disk */
	int disk;    /* fd which is open with disk file */
	struct {
		int offset;
	}swapout;
	/* read from disk. Data can store in /dev/shm or reply->in */
	struct {
		int offset;
	}swapin;
	mmap_t map;
	mem_t *mem;
	cache_control_t cc;
}reply_t;

typedef struct {
	int cfd; /* client fd */
	int sfd; /* server fd */
    struct in_addr client_addr;
    struct in_addr server_addr;
	/* thread */
	thread_t *thread;
	/* events */
	event_t *client_event;
	event_t *server_event;
	event_t *timer;
	buffer_t *in;  /* bufffer of client data */
	struct list_head requests;  /* a list of request */
	int nrequests;
	/* connections list, in active or waiting? */
	struct list_head list;
}conn_t;	

typedef struct {
	struct list_head list;
	char *url_path;
	char *host;
	int remote_port;
	int proto;
	int hit_state;
	int log_state; /* write to access.log */
	int cacheable;
	int content_length;
	int ims;
	header_t *headers;
	buffer_t *body;  /* assert body->offset == content_length */
	http_version_t version;
	method_t method;
	cache_control_t cc;
	reply_t *reply;  /* reply for the request */
	cache_file_t *cache;
	conn_t *con;
}request_t;

extern conn_t *conn_new(int cfd, short cfl, PF *ch, void *arg, struct in_addr *client_addr, event_base_t *base, thread_t *thread) ;
extern void conn_free(conn_t *con);
extern void conn_timeout_set(event_t *ev, PF *handler, void *arg, int timeout, event_base_t *base);
extern void conn_timeout_handle(int fd, short flag, void *arg);
extern void conn_request_read(int fd, short flag, void *arg);
/* event handler */
extern int timeout_update(event_t *ev, PF *handler, void *arg, int timeout);
extern int timer_update(event_t *ev, PF *handler, void *arg, int sec, int usec);
extern char *hit_state_string(int state);
/* data search */
extern int mem_cache_find(request_t *r, cache_file_t *cache);
extern int shm_cache_find(request_t *r, cache_file_t *cache);
extern int disk_find(request_t *r, cache_file_t *cache);
extern int disk_map(reply_t *rep, buffer_t *file, int low, int high);
extern int disk_map2(reply_t *rep, buffer_t *file, int low, int high);
extern void disk_map_reset(mmap_t *map);
extern void disk_map_free(mmap_t *map);
extern char *data_state_to_string(int state);
/* rfc1123 time */
extern char *mkrfc1123_r(time_t t, char *buf, size_t size) ;
extern time_t parse_rfc1123(const char *str, int len);
#endif
